การจัดการทรัพยากรด้วย React use Hook: การเพิ่มประสิทธิภาพวงจรชีวิตของทรัพยากรเพื่อประสิทธิภาพสูงสุด | MLOG | MLOG

คำอธิบาย:

ตัวอย่างที่ 2: การจัดการการเชื่อมต่อ WebSocket

ตัวอย่างนี้แสดงวิธีการจัดการการเชื่อมต่อ WebSocket โดยใช้ "use" Hook และ custom resource wrapper

            import React, { useState, useEffect, use } from 'react';

const createWebSocketResource = (url) => {
  let socket;
  let status = 'pending';
  let messageQueue = [];
  let listeners = [];

  const connect = () => {
    return new Promise((resolve, reject) => {
      socket = new WebSocket(url);

      socket.onopen = () => {
        status = 'connected';
        resolve();
        // Send queued messages
        messageQueue.forEach(msg => socket.send(msg));
        messageQueue = [];
      };

      socket.onerror = (error) => {
        status = 'error';
        reject(error);
      };

      socket.onmessage = (event) => {
        listeners.forEach(listener => listener(event.data));
      };

      socket.onclose = () => {
        status = 'closed';
        listeners = []; // Clear listeners to avoid memory leaks
      };
    });
  };

  const promise = connect();

  return {
    read() {
      use(promise);
    },
    send(message) {
      if (status === 'connected') {
        socket.send(message);
      } else {
        messageQueue.push(message);
      }
    },
    subscribe(listener) {
      listeners.push(listener);
      return () => {
        listeners = listeners.filter(l => l !== listener);
      };
    },
    close() {
        if (socket && socket.readyState !== WebSocket.CLOSED) {
            socket.close();
        }
    }
  };
};

function WebSocketComponent({ url }) {
  const socketResource = createWebSocketResource(url);
  // Suspend until connected
  socketResource.read();
  const [message, setMessage] = useState('');
  const [receivedMessages, setReceivedMessages] = useState([]);

  useEffect(() => {
    const unsubscribe = socketResource.subscribe(data => {
      setReceivedMessages(prevMessages => [...prevMessages, data]);
    });
    return () => {
        unsubscribe();
        socketResource.close();
    };
  }, [socketResource]);

  const sendMessage = () => {
    socketResource.send(message);
    setMessage('');
  };

  return (
    
setMessage(e.target.value)} />
Received Messages:
    {receivedMessages.map((msg, index) => (
  • {msg}
  • ))}
); } function App() { return ( Connecting to WebSocket...
}> ); } export default App;

คำอธิบาย:

ตัวอย่างที่ 3: การจัดการ File Handles

ตัวอย่างนี้แสดงการจัดการทรัพยากรด้วย "use" Hook โดยใช้ file handles ของ NodeJS (สิ่งนี้จะทำงานได้ในสภาพแวดล้อม NodeJS เท่านั้นและมีวัตถุประสงค์เพื่อแสดงแนวคิดเกี่ยวกับวงจรชีวิตของทรัพยากร)

            // This example is designed for a NodeJS environment

const fs = require('node:fs/promises');
import React, { use } from 'react';

const createFileHandleResource = async (filePath) => {
  let fileHandle;

  const openFile = async () => {
    fileHandle = await fs.open(filePath, 'r');
    return fileHandle;
  };

  const promise = openFile();

  return {
    read() {
      return use(promise);
    },
    async close() {
      if (fileHandle) {
        await fileHandle.close();
        fileHandle = null;
      }
    },
    async readContents() {
      const handle = use(promise);
      const buffer = await handle.readFile();
      return buffer.toString();
    }
  };
};


function FileViewer({ filePath }) {
  const fileHandleResource = createFileHandleResource(filePath);
  const contents = fileHandleResource.readContents();

  React.useEffect(() => {
    return () => {
      // Cleanup when the component unmounts
      fileHandleResource.close();
    };
  }, [fileHandleResource]);

  return (
    

File Contents:

{contents}
); } // Example Usage async function App() { const filePath = 'example.txt'; await fs.writeFile(filePath, 'Hello, world!\nThis is a test file.'); return (
); } export default App;

คำอธิบาย:

เทคนิคขั้นสูง: Error Boundaries, Resource Pooling และ Server Components

นอกเหนือจากตัวอย่างพื้นฐานแล้ว "use" Hook ยังสามารถใช้ร่วมกับฟีเจอร์อื่นๆ ของ React เพื่อใช้กลยุทธ์การจัดการทรัพยากรที่ซับซ้อนยิ่งขึ้น

Error Boundaries: การจัดการข้อผิดพลาดอย่างนุ่มนวล

Error boundaries เป็นคอมโพเนนต์ของ React ที่ดักจับข้อผิดพลาด JavaScript ที่ใดก็ได้ใน component tree ของลูกๆ, บันทึกข้อผิดพลาดเหล่านั้น และแสดง UI สำรองแทนที่จะทำให้ component tree ทั้งหมดล่ม เมื่อใช้ "use" Hook สิ่งสำคัญคือต้องห่อหุ้มคอมโพเนนต์ของคุณด้วย error boundaries เพื่อจัดการข้อผิดพลาดที่อาจเกิดขึ้นระหว่างการดึงข้อมูลหรือการเริ่มต้นทรัพยากร

            import React, { Component } from 'react';

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    console.error(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return 

Something went wrong.

; } return this.props.children; } } function App() { return ( Loading...
}> ); }

Resource Pooling: การเพิ่มประสิทธิภาพการใช้ทรัพยากรซ้ำ

ในบางสถานการณ์ การสร้างและทำลายทรัพยากรบ่อยครั้งอาจมีค่าใช้จ่ายสูง Resource pooling เกี่ยวข้องกับการรักษากลุ่มของทรัพยากรที่ใช้ซ้ำได้เพื่อลดค่าใช้จ่ายในการสร้างและทำลายทรัพยากร แม้ว่า "use" hook จะไม่ได้ implement resource pooling โดยเนื้อแท้ แต่ก็สามารถใช้ร่วมกับการ implement resource pool แยกต่างหากได้

พิจารณา connection pool ของฐานข้อมูล แทนที่จะสร้างการเชื่อมต่อใหม่สำหรับทุกๆ คำขอ คุณสามารถรักษากลุ่มของการเชื่อมต่อที่สร้างไว้ล่วงหน้าและนำกลับมาใช้ใหม่ได้ "use" Hook สามารถใช้เพื่อจัดการการรับและการปล่อยการเชื่อมต่อจาก pool

(ตัวอย่างเชิงแนวคิด - การ implement จะแตกต่างกันไปขึ้นอยู่กับทรัพยากรและไลบรารี pooling เฉพาะ):

            // Conceptual Example (not a complete, runnable implementation)

import React, { use } from 'react';
// Assume a database connection pool library exists
import { getConnectionFromPool, releaseConnectionToPool } from './dbPool';

const createDbConnectionResource = () => {
  let connection;

  const acquireConnection = async () => {
    connection = await getConnectionFromPool();
    return connection;
  };

  const promise = acquireConnection();

  return {
    read() {
      return use(promise);
    },
    release() {
      if (connection) {
        releaseConnectionToPool(connection);
        connection = null;
      }
    },
    query(sql) {
      const conn = use(promise);
      return conn.query(sql);
    }
  };
};

function MyDataComponent() {
  const dbResource = createDbConnectionResource();

  React.useEffect(() => {
    return () => {
      dbResource.release();
    };
  }, [dbResource]);

  const data = dbResource.query('SELECT * FROM my_table');
  return 
{data}
; }

React Server Components (RSCs): บ้านตามธรรมชาติของ "use" Hook

"use" Hook ถูกออกแบบมาสำหรับ React Server Components ในตอนแรก RSCs ทำงานบนเซิร์ฟเวอร์ ทำให้คุณสามารถดึงข้อมูลและดำเนินการอื่นๆ ฝั่งเซิร์ฟเวอร์ได้โดยไม่ต้องส่งโค้ดไปยังไคลเอ็นต์ ซึ่งช่วยปรับปรุงประสิทธิภาพอย่างมากและลดขนาด bundle ของ JavaScript ฝั่งไคลเอ็นต์

ใน RSCs "use" Hook สามารถใช้เพื่อดึงข้อมูลโดยตรงจากฐานข้อมูลหรือ API โดยไม่จำเป็นต้องใช้ไลบรารีการดึงข้อมูลฝั่งไคลเอ็นต์ ข้อมูลจะถูกดึงบนเซิร์ฟเวอร์ และ HTML ที่ได้จะถูกส่งไปยังไคลเอ็นต์ ซึ่งจะถูก hydrate โดย React

เมื่อใช้ "use" Hook ใน RSCs สิ่งสำคัญคือต้องตระหนักถึงข้อจำกัดของ RSCs เช่น การไม่มี state และ event handlers ฝั่งไคลเอ็นต์ อย่างไรก็ตาม RSCs สามารถใช้ร่วมกับคอมโพเนนต์ฝั่งไคลเอ็นต์เพื่อสร้างแอปพลิเคชันที่มีประสิทธิภาพและทรงพลังได้

แนวทางปฏิบัติที่ดีที่สุดสำหรับการจัดการทรัพยากรอย่างมีประสิทธิภาพด้วย "use"

เพื่อเพิ่มประโยชน์สูงสุดของ "use" Hook สำหรับการจัดการทรัพยากร ให้ปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:

ข้อผิดพลาดทั่วไปและวิธีหลีกเลี่ยง

แม้ว่า "use" Hook จะมีประโยชน์มากมาย แต่สิ่งสำคัญคือต้องตระหนักถึงข้อผิดพลาดที่อาจเกิดขึ้นและวิธีหลีกเลี่ยง

สรุป: การนำ "use" Hook มาใช้เพื่อแอปพลิเคชัน React ที่มีประสิทธิภาพสูงสุด

React "use" Hook แสดงถึงความก้าวหน้าที่สำคัญในการจัดการทรัพยากรภายในแอปพลิเคชัน React ด้วยการทำให้การจัดการข้อมูลแบบอะซิงโครนัสง่ายขึ้น, การล้างทรัพยากรโดยอัตโนมัติ และการผสานรวมกับ Suspense อย่างราบรื่น มันช่วยให้นักพัฒนาสามารถสร้างแอปพลิเคชันที่มีประสิทธิภาพ, บำรุงรักษาง่าย และเป็นมิตรต่อผู้ใช้มากขึ้น

โดยการทำความเข้าใจแนวคิดหลัก, สำรวจตัวอย่างที่นำไปใช้ได้จริง และปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุด คุณสามารถใช้ประโยชน์จาก "use" Hook ได้อย่างมีประสิทธิภาพเพื่อเพิ่มประสิทธิภาพวงจรชีวิตของทรัพยากรและปลดล็อกศักยภาพสูงสุดของแอปพลิเคชัน React ของคุณ ในขณะที่ React ยังคงพัฒนาต่อไป "use" Hook จะมีบทบาทสำคัญมากขึ้นในการกำหนดอนาคตของการจัดการทรัพยากรในระบบนิเวศของ React อย่างไม่ต้องสงสัย